package com.hongji.lms5xxcommunicator.grid;

import com.hongji.lms5xxcommunicator.entity.ScanPointEntity;
import com.hongji.lms5xxcommunicator.grid.core.GridSpec;
import com.hongji.lms5xxcommunicator.grid.core.UpdateMode;
import com.hongji.lms5xxcommunicator.grid.export.GridDeltaPayload;

import java.util.List;

/**
 * 栅格聚合与体积的门面接口（已移除区域峰值相关接口）。
 *
 * <p><b>职责与行为：</b></p>
 * <ul>
 *   <li><b>配置：</b>更新策略（均值/替换）、体积参数（基线/负值截断）。</li>
 *   <li><b>数据：</b>按原始点（实体/数组）进行增量合并；支持越界自动扩容。</li>
 *   <li><b>体积：</b>提供实时的体积差分路径（WithDelta）；普通增量仅使体积缓存失效。</li>
 *   <li><b>范围：</b>对外暴露观测到的 z 范围（min/max）与范围版本号（rangeSeq），用于前端自动色标。</li>
 * </ul>
 *
 * <p><b>线程安全：</b>除非实现类另行声明，本接口的典型实现不保证并发安全；多线程写入时请在调用方同步。</p>
 */
public interface RasterGridApi {

    // =========================
    //        配置阶段
    // =========================

    /**
     * 设置更新策略。
     *
     * <p>可选：</p>
     * <ul>
     *   <li>{@link UpdateMode#MEAN}：同格点做均值合并（历史 + 当前）。</li>
     *   <li>{@link UpdateMode#REPLACE_SINGLE_ELSE_MEAN}：单点命中格直接替换，否则按帧内均值与历史做加权均值。</li>
     *   <li>{@link UpdateMode#REPLACE}：<b>严格替换</b>，命中即用最新 z 覆盖历史（推荐用于实时展示）。</li>
     * </ul>
     *
     * @param mode 更新模式；传 {@code null} 等同 {@link UpdateMode#REPLACE}
     * @return this（链式调用）
     */
    RasterGridApi setUpdateMode(UpdateMode mode);

    /**
     * 配置体积参数并触发体积缓存的全量重算。
     *
     * <p>当 {@code clampNegative=true} 时，对 (均值 z - baseline) 的负值将被截断为 0。</p>
     *
     * @param baseline      体积基线（低于该值的 z 以基线参与体积计算）
     * @param clampNegative 是否对负贡献截断为 0
     */
    void configureVolume(double baseline, boolean clampNegative);

    // =========================
    //        查询/管理
    // =========================

    /**
     * 获取当前体积。
     *
     * <p>若缓存未就绪会计算一次并缓存。</p>
     *
     * @return 当前体积值
     */
    double getVolume();

    /**
     * 清空全部数据；并将体积缓存置为未就绪。
     * <p>实现应同时重置 z 范围与范围版本号（rangeSeq）。</p>
     */
    void clear();

    /**
     * 返回当前网格规格。
     *
     * @return {@link GridSpec}
     */
    GridSpec spec();

    /**
     * 返回观测到的最小 z。
     * <p>若尚无观测数据，建议实现返回 0。</p>
     */
    double getObservedMinZ();

    /**
     * 返回观测到的最大 z。
     * <p>若尚无观测数据，建议实现返回 0。</p>
     */
    double getObservedMaxZ();

    /**
     * 返回 z 范围的“版本号”（单调递增）。
     * <p>当观测到的 zMin 降低或 zMax 升高时，版本号自增一次；前端据此触发一次性整幅重染色。</p>
     */
    long getRangeSeq();

    // =========================
    //   增量合并（不做体积差分）
    // =========================

    /**
     * 增量合并（实体）——不维护体积差分。
     *
     * <p>将新点合并进网格，并使体积缓存失效（下次 {@link #getVolume()} 会重算）。</p>
     *
     * @param entities 新批次点实体列表
     */
    void mergePoints(List<ScanPointEntity> entities);

    /**
     * 增量合并（XYZ 数组）——不维护体积差分。
     *
     * @param xs X 数组（长度与 {@code ys}、{@code zs} 相同）
     * @param ys Y 数组
     * @param zs Z 数组
     */
    void mergeXYZ(double[] xs, double[] ys, double[] zs);

    // =========================
    //   体积差分 + 增量结果（实时）
    // =========================

    /**
     * 合并（实体）+ 实时体积差分 + 增量导出（不触发扩容路径）。
     *
     * <p>仅对本批触达格 O(#touched) 做体积差分与增量导出。</p>
     *
     * @param entities       本批次点
     * @param minCountFilter 若非 {@code null} 且 ≥ 1，则过滤 count &lt; 阈值 的格
     * @return 增量格点 + 最新体积（{@code payload.full = false}）
     */
    GridDeltaPayload mergeWithDelta(List<ScanPointEntity> entities, Integer minCountFilter);
}
